<template>
  <a-drawer class="basic-drawer" @close="onClose" v-bind="getBindValues">
    <template #title v-if="!$slots.title">
      <DrawerHeader :title="getMergeProps.title" :isDetail="isDetail" :showDetailBack="showDetailBack" @close="onClose">
        <template #titleToolbar>
          <slot name="titleToolbar"></slot>
        </template>
      </DrawerHeader>
    </template>
    <template v-else #title>
      <slot name="title"></slot>
    </template>
    <template #closeIcon>
      <IconFont iconType="icon-close_icon" />
    </template>
    <slot name="contentExtra"></slot>
    <ScrollContainer :style="getScrollContentStyle" v-loading="getLoading" :loading-tip="loadingText || '加载中...'">
      <slot></slot>
    </ScrollContainer>
    <DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk" :height="getFooterHeight">
      <template #[item]="data" v-for="item in Object.keys($slots)">
        <slot :name="item" v-bind="data || {}"></slot>
      </template>
    </DrawerFooter>
  </a-drawer>
</template>
<script lang="ts">
import type { DrawerInstance, DrawerProps } from './typing'
import type { CSSProperties } from 'vue'
import { defineComponent, ref, computed, watch, unref, nextTick, toRaw, getCurrentInstance } from 'vue'
import { isFunction, isNumber } from '@/utils/is'
import { deepMerge } from '@/utils'
import DrawerFooter from './components/DrawerFooter.vue'
import DrawerHeader from './components/DrawerHeader.vue'
import ScrollContainer from '@/components/ScrollContainer/index.vue'
import { basicProps } from './props'
import { useAttrs } from '@/hooks/useAttrs'
import IconFont from '@/components/IconFont/index.vue'

export default defineComponent({
  components: { ScrollContainer, DrawerFooter, DrawerHeader, IconFont },
  inheritAttrs: false,
  props: basicProps,
  emits: ['visible-change', 'ok', 'close', 'register'],
  setup(props, { emit }) {
    const visibleRef = ref(false)
    const attrs = useAttrs()
    const propsRef = ref<Partial<Nullable<DrawerProps>>>(null)

    const drawerInstance: DrawerInstance = {
      setDrawerProps: setDrawerProps,
      emitVisible: undefined
    }

    const instance = getCurrentInstance()

    instance && emit('register', drawerInstance, instance.uid)

    const getMergeProps = computed((): DrawerProps => {
      return deepMerge(toRaw(props), unref(propsRef))
    })

    const getProps = computed((): DrawerProps => {
      const opt = {
        placement: 'right',
        ...unref(attrs),
        ...unref(getMergeProps),
        visible: unref(visibleRef)
      }
      // opt.title = undefined
      const { isDetail, width, wrapClassName, getContainer, isAbsolute } = opt
      if (isAbsolute) {
        opt.class = wrapClassName ? `${wrapClassName} basic-drawer__abosult` : 'basic-drawer__abosult'
      }
      if (isDetail) {
        opt.title = undefined
        if (!width) {
          opt.width = '100%'
        }
        const detailCls = `basic-drawer__detail`
        opt.class = wrapClassName ? `${wrapClassName} ${detailCls}` : detailCls

        if (!getContainer) {
          opt.getContainer = `.page-wrapper` as any
        }
      }
      return opt as DrawerProps
    })

    const getBindValues = computed((): DrawerProps => {
      return {
        ...attrs,
        ...unref(getProps)
      }
    })

    // Custom implementation of the bottom button,
    const getFooterHeight = computed(() => {
      const { footerHeight, showFooter } = unref(getProps)
      if (showFooter && footerHeight) {
        return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`
      }
      return `0px`
    })

    const getScrollContentStyle = computed((): CSSProperties => {
      const footerHeight = unref(getFooterHeight)
      // 额外高度
      const { extraScrollHeight } = unref(getProps)
      const extraScrollHeightValue = isNumber(extraScrollHeight)
        ? `${extraScrollHeight}px`
        : `${extraScrollHeight.replace('px', '')}px`

      return {
        position: 'relative',
        height:
          extraScrollHeightValue !== '0px'
            ? `calc(100% - ${footerHeight} - ${extraScrollHeightValue})`
            : `calc(100% - ${footerHeight})`
      }
    })

    const getLoading = computed(() => {
      return !!unref(getProps)?.loading
    })

    watch(
      () => props.visible,
      (newVal, oldVal) => {
        if (newVal !== oldVal) visibleRef.value = newVal
      },
      { deep: true }
    )

    watch(
      () => visibleRef.value,
      (visible) => {
        nextTick(() => {
          emit('visible-change', visible)
          instance && drawerInstance.emitVisible?.(visible, instance.uid)
        })
      }
    )

    // Cancel event
    async function onClose(e: Recordable) {
      const { closeFunc } = unref(getProps)
      emit('close', e)
      if (closeFunc && isFunction(closeFunc)) {
        const res = await closeFunc()
        visibleRef.value = !res
        return
      }
      visibleRef.value = false
    }

    function setDrawerProps(props: Partial<DrawerProps>): void {
      // Keep the last setDrawerProps
      propsRef.value = deepMerge(unref(propsRef) || ({} as any), props)

      if (Reflect.has(props, 'visible')) {
        visibleRef.value = !!props.visible
      }
    }

    function handleOk() {
      emit('ok')
    }

    return {
      onClose,
      getMergeProps: getMergeProps as any,
      getScrollContentStyle,
      getProps: getProps as any,
      getLoading,
      getBindValues,
      getFooterHeight,
      handleOk
    }
  }
})
</script>
